/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package codeclz77;

import codeclz77.bean.Lz77;
import codeclz77.bean.Triplet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author Douglas
 */
public class Code {

    private Lz77 lz;

    public Code() {
    }

    public Code(Lz77 lz) {
        this.lz = lz;
    }

    public void addSymbol(char newSymbol) {

        lz.addBuffer(newSymbol);
        if (lz.getLookAhead() > (char) (lz.getBufferSize())) {
            return;
        }

        int quantSwaps = geraTriplet();
        for (int i = 0; i <= quantSwaps; i++) {
            if (lz.getBufferSize() > (int) (lz.getLookAhead() + lz.getSearchBuffer())) {
                lz.swapBuffer();
            } else {
                lz.setPointer(lz.getPointer() + 1);
            }
        }
    }

    public void addFinal() {

        addSymbol('$');
        ArrayList<Character> bufferComparacao = geraList();
        while (lz.getLookAhead() != 0) {

            if (lz.getLookAhead() > bufferComparacao.get(bufferComparacao.size() - lz.getPointer())) {

                lz.setLookAhead(bufferComparacao.get(bufferComparacao.size() - lz.getPointer()));

            }
            int quantSwaps = geraTriplet();
            for (int i = 0; i <= quantSwaps; i++) {
                if (lz.getBufferSize() > (int) (lz.getLookAhead() + lz.getSearchBuffer())) {
                    lz.swapBuffer();
                } else {
                    lz.setPointer(lz.getPointer() + 1);
                }

            }

        }

    }

    /**
     * @return the lz
     */
    public Lz77 getLz() {
        return lz;
    }

    /**
     * @param lz the lz to set
     */
    public void setLz(Lz77 lz) {
        this.lz = lz;
    }

    private int geraTriplet() {
        String strCompara;
        Triplet tri = new Triplet();
        ArrayList<Character> bufferComparacao = geraList();
        for (int numSimbolos = 1; numSimbolos <= (int) lz.getLookAhead(); numSimbolos++) {
            strCompara = pegaString(numSimbolos);
            Iterator<Character> itr = lz.buffer.iterator();

            String strBuffer = "";
            int index;
            int tamanho = 0;
            for (index = 0; index < bufferComparacao.size() && !(strCompara.equals(strBuffer)); index++) {
                strBuffer = "";
                for (tamanho = 1; tamanho <= numSimbolos; tamanho++) {
                    strBuffer += strBuffer + bufferComparacao.get(index + tamanho);
                }
            }

            if (strCompara.equals(strBuffer)) {

                tri.setMatchLength((char) tamanho);
                tri.setOffset((char) (lz.getPointer() - index));
                tri.setCodeword(bufferComparacao.get(index + numSimbolos));
                lz.addTriplet(tri);
                return tamanho;

            }
        }
        return 0;

    }

    private String pegaString(int numSimbolos) {
        String strCompara = "";
        Iterator<Character> itr = lz.buffer.iterator();
// Posiciona o buffer de leitura do Deque no índice do ponteiro
        for (int i = 0; itr.hasNext() && i < lz.getPointer(); i++) {
            itr.next();
        }
// A partir do ponto localizado, concatena a quantidade de caracteres passado
        for (int i = 0; itr.hasNext() && i <= numSimbolos; i++) {
            strCompara += strCompara + itr.next();
        }
        return strCompara;
    }

    private ArrayList<Character> geraList() {
        ArrayList<Character> bufferComparacao = new ArrayList();
        Iterator<Character> itr = lz.buffer.iterator();
// Posiciona o buffer de leitura do Deque no índice do ponteiro
        while (itr.hasNext()) {
            bufferComparacao.add(itr.next());
        }
        return bufferComparacao;

    }
}
